home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / sox / sox.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  17KB  |  754 lines

  1. /*
  2.  * July 5, 1991
  3.  * Copyright 1991 Lance Norskog And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained. 
  6.  * Lance Norskog And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. #include "st.h"
  11. #if    defined(unix) || defined(AMIGA)
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #endif
  15. #ifdef    __STDC__
  16. #include <stdarg.h>
  17. #else
  18. #include <varargs.h>
  19. #endif
  20. #include <ctype.h>
  21. #include <string.h>
  22. #ifdef VMS
  23. #include <errno.h>
  24. #include <perror.h>
  25. #define LASTCHAR        ']'
  26. #else
  27. #include <errno.h>
  28. #define LASTCHAR        '/'
  29. #endif
  30.  
  31. /*
  32.  * SOX main program.
  33.  *
  34.  * Rewrite for new nicer option syntax.  July 13, 1991.
  35.  * Rewrite for separate effects library.  Sep. 15, 1991.
  36.  */
  37.  
  38. #ifdef AMIGA
  39. /* This is the Amiga version string */
  40. char amiversion[AmiVerSize]=AmiVerChars;      
  41. #endif /* AMIGA */
  42.  
  43.  
  44. EXPORT float volume = 1.0;    /* expansion coefficient */
  45. int dovolume = 0;
  46. int clipped = 0;    /* Volume change clipping errors */
  47.  
  48. EXPORT float amplitude = 1.0;    /* Largest sample so far */
  49.  
  50. EXPORT int writing = 0;    /* are we writing to a file? */
  51.  
  52. /* export flags */
  53. EXPORT int verbose = 0;    /* be noisy on stderr */
  54. EXPORT int summary = 0;    /* just print summary of information */
  55.  
  56. long ibuf[BUFSIZ];    /* Intermediate processing buffer */
  57. long obuf[BUFSIZ];    /* Intermediate processing buffer */
  58.  
  59.  
  60. long volumechange();
  61.  
  62. #ifdef    DOS
  63. char writebuf[BUFSIZ];    /* output write buffer */
  64. #endif
  65.  
  66. void    gettype(), geteffect(), checkeffect();
  67.  
  68. EXPORT struct soundstream informat, outformat;
  69.  
  70. char *myname;
  71.  
  72. ft_t ft;
  73. struct effect eff;
  74. char *ifile, *ofile, *itype, *otype;
  75. IMPORT char *optarg;
  76. IMPORT int optind;
  77.  
  78. main(n, args)
  79. int n;
  80. char **args;
  81. {
  82.     myname = args[0];
  83.     init();
  84.     
  85.     ifile = ofile = NULL;
  86.  
  87.     /* Get input format options */
  88.     ft = &informat;
  89.     doopts(n, args);
  90.     /* Get input file */
  91.     if (optind >= n)
  92. #ifndef    VMS
  93.         usage("No input file?");
  94. #else
  95.         /* I think this is the VMS patch, but am not certain */
  96.         fail("Input file required");    
  97. #endif
  98.     ifile = args[optind];
  99.     if (! strcmp(ifile, "-"))
  100.         ft->fp = stdin;
  101.     else if ((ft->fp = fopen(ifile, READBINARY)) == NULL)
  102.         fail("Can't open input file '%s': %s", 
  103.             ifile, strerror(errno));
  104.     ft->filename = ifile;
  105.     optind++;
  106.  
  107.     /* Let -e allow no output file, just do an effect */
  108.     if (optind < n) {
  109.         if (strcmp(args[optind], "-e")) {
  110.         /* Get output format options */
  111.         ft = &outformat;
  112.         doopts(n, args);
  113.         /* Get output file */
  114.         if (optind >= n)
  115.             usage("No output file?");
  116.         ofile = args[optind];
  117.         ft->filename = ofile;
  118.         /*
  119.          * There are two choices here:
  120.          *    1) stomp the old file - normal shell "> file" behavior
  121.          *    2) fail if the old file already exists - csh mode
  122.          */
  123.         if (! strcmp(ofile, "-"))
  124.             ft->fp = stdout;
  125.         else {
  126. #ifdef    unix
  127.              /*    
  128.              * Remove old file if it's a text file, but 
  129.               * preserve Unix /dev/sound files.  I'm not sure
  130.              * this needs to be here, but it's not hurting
  131.              * anything.
  132.              */
  133.             if ((ft->fp = fopen(ofile, WRITEBINARY)) && 
  134.                    (filetype(fileno(ft->fp)) == S_IFREG)) {
  135.                 fclose(ft->fp);
  136.                 unlink(ofile);
  137.                 creat(ofile, 0666);
  138.                 ft->fp = fopen(ofile, WRITEBINARY);
  139.             }
  140. #else
  141.             ft->fp = fopen(ofile, WRITEBINARY);
  142. #endif
  143.             if (ft->fp == NULL)
  144.                 fail("Can't open output file '%s': %s", 
  145.                     ofile, strerror(errno));
  146. #ifdef    DOS
  147.             if (setvbuf (ft->fp,writebuf,_IOFBF,sizeof(writebuf)))
  148.                 fail("Can't set write buffer");
  149. #endif
  150.         }
  151.         writing = 1;
  152.         }
  153.         optind++;
  154.     }
  155.  
  156.     /* ??? */
  157. /*
  158.     if ((optind < n) && !writing && !eff.name)
  159.         fail("Can't do an effect without an output file!");
  160. */
  161.  
  162.     /* Get effect name */
  163.     if (optind < n) {
  164.         eff.name = args[optind];
  165.         optind++;
  166.         geteffect(&eff);
  167.         (* eff.h->getopts)(&eff, n - optind, &args[optind]);
  168.     }
  169.  
  170.     /* 
  171.      * If we haven't specifically set an output file 
  172.      * don't write a file; we could be doing a summary
  173.      * or a format check.
  174.      */
  175. /*
  176.     if (! ofile)
  177.         usage("Must be given an output file name");
  178. */
  179.     if (! ofile)
  180.         writing = 0;
  181.     /* Check global arguments */
  182.     if (volume <= 0.0)
  183.         fail("Volume must be greater than 0.0");
  184. #if    defined(unix) || defined(AMIGA)
  185.     informat.seekable  = (filetype(fileno(informat.fp)) == S_IFREG);
  186.     outformat.seekable = (filetype(fileno(outformat.fp)) == S_IFREG); 
  187. #else
  188. #if    defined(DOS)
  189.     informat.seekable  = 1;
  190.     outformat.seekable = 1;
  191. #else
  192.     informat.seekable  = 0;
  193.     outformat.seekable = 0;
  194. #endif
  195. #endif
  196.  
  197.     /* If file types have not been set with -t, set from file names. */
  198.     if (! informat.filetype) {
  199.         if (informat.filetype = strrchr(ifile, LASTCHAR))
  200.             informat.filetype++;
  201.         else
  202.             informat.filetype = ifile;
  203.         if (informat.filetype = strrchr(informat.filetype, '.'))
  204.             informat.filetype++;
  205.         else /* Default to "auto" */
  206.             informat.filetype = "auto";
  207.     }
  208.     if (writing && ! outformat.filetype) {
  209.         if (outformat.filetype = strrchr(ofile, LASTCHAR))
  210.             outformat.filetype++;
  211.         else
  212.             outformat.filetype = ofile;
  213.         if (outformat.filetype = strrchr(outformat.filetype, '.'))
  214.             outformat.filetype++;
  215.     }
  216.     /* Default the input comment to the filename. 
  217.      * The output comment will be assigned when the informat 
  218.      * structure is copied to the outformat. 
  219.      */
  220.     informat.comment = informat.filename;
  221.  
  222.     process();
  223.     statistics();
  224.     exit(0);
  225. }
  226.  
  227. doopts(n, args)
  228. int n;
  229. char **args;
  230. {
  231.     int c;
  232.     char *str;
  233.  
  234.     while ((c = getopt(n, args, "r:v:t:c:suUAbwlfdDxSV")) != -1) {
  235.         switch(c) {
  236.         case 't':
  237.             if (! ft) usage("-t");
  238.             ft->filetype = optarg;
  239.             if (ft->filetype[0] == '.')
  240.                 ft->filetype++;
  241.             break;
  242.  
  243.         case 'r':
  244.             if (! ft) usage("-r");
  245.             str = optarg;
  246.             if ((! sscanf(str, "%lu", &ft->info.rate)) ||
  247.                     (ft->info.rate <= 0))
  248.                 fail("-r must be given a positive integer");
  249.             break;
  250.         case 'v':
  251.             if (! ft) usage("-v");
  252.             str = optarg;
  253.             if ((! sscanf(str, "%e", &volume)) ||
  254.                     (volume <= 0))
  255.                 fail("Volume value '%s' is not a number",
  256.                     optarg);
  257.             dovolume = 1;
  258.             break;
  259.  
  260.         case 'c':
  261.             if (! ft) usage("-c");
  262.             str = optarg;
  263.             if (! sscanf(str, "%d", &ft->info.channels))
  264.                 fail("-c must be given a number");
  265.             break;
  266.         case 'b':
  267.             if (! ft) usage("-b");
  268.             ft->info.size = BYTE;
  269.             break;
  270.         case 'w':
  271.             if (! ft) usage("-w");
  272.             ft->info.size = WORD;
  273.             break;
  274.         case 'l':
  275.             if (! ft) usage("-l");
  276.             ft->info.size = LONG;
  277.             break;
  278.         case 'f':
  279.             if (! ft) usage("-f");
  280.             ft->info.size = FLOAT;
  281.             break;
  282.         case 'd':
  283.             if (! ft) usage("-d");
  284.             ft->info.size = DOUBLE;
  285.             break;
  286.         case 'D':
  287.             if (! ft) usage("-D");
  288.             ft->info.size = IEEE;
  289.             break;
  290.  
  291.         case 's':
  292.             if (! ft) usage("-s");
  293.             ft->info.style = SIGN2;
  294.             break;
  295.         case 'u':
  296.             if (! ft) usage("-u");
  297.             ft->info.style = UNSIGNED;
  298.             break;
  299.         case 'U':
  300.             if (! ft) usage("-U");
  301.             ft->info.style = ULAW;
  302.             break;
  303.         case 'A':
  304.             if (! ft) usage("-A");
  305.             ft->info.style = ALAW;
  306.             break;
  307.         
  308.         case 'x':
  309.             if (! ft) usage("-x");
  310.             ft->swap = 1;
  311.             break;
  312.         
  313. /*  stat effect does this ?
  314.         case 'S':
  315.             summary = 1;
  316.             break;
  317. */
  318.         case 'V':
  319.             verbose = 1;
  320.             break;
  321.         }
  322.     }
  323. }
  324.  
  325. init() {
  326.  
  327.     /* init files */
  328.     informat.info.rate      = outformat.info.rate  = 0;
  329.     informat.info.size      = outformat.info.size  = -1;
  330.     informat.info.style     = outformat.info.style = -1;
  331.     informat.info.channels  = outformat.info.channels = -1;
  332.     informat.comment   = outformat.comment = NULL;
  333.     informat.swap      = 0;
  334.     informat.filetype  = outformat.filetype  = (char *) 0;
  335.     informat.fp        = stdin;
  336.     outformat.fp       = stdout;
  337.     informat.filename  = "input";
  338.     outformat.filename = "output";
  339. }
  340.  
  341. /* 
  342.  * Process input file -> effect -> output file
  343.  *    one buffer at a time
  344.  */
  345.  
  346. process() {
  347.     long isamp, osamp, istart;
  348.     long i, idone, odone;
  349.  
  350.     gettype(&informat);
  351.     if (writing)
  352.         gettype(&outformat);
  353.     /* Read and write starters can change their formats. */
  354.     (* informat.h->startread)(&informat);
  355.     checkformat(&informat);
  356.     report("Input file: using sample rate %u\n\tsize %s, style %s, %d %s",
  357.         informat.info.rate, sizes[informat.info.size], 
  358.         styles[informat.info.style], informat.info.channels, 
  359.         (informat.info.channels > 1) ? "channels" : "channel");
  360.     if (informat.comment)
  361.         report("Input file: comment \"%s\"\n",
  362.             informat.comment);
  363.     if (writing) {
  364.         copyformat(&informat, &outformat);
  365.         (* outformat.h->startwrite)(&outformat);
  366.         checkformat(&outformat);
  367.         cmpformats(&informat, &outformat);
  368.     report("Output file: using sample rate %u\n\tsize %s, style %s, %d %s",
  369.         outformat.info.rate, sizes[outformat.info.size], 
  370.         styles[outformat.info.style], outformat.info.channels, 
  371.         (outformat.info.channels > 1) ? "channels" : "channel");
  372.         if (outformat.comment)
  373.             report("Output file: comment \"%s\"\n",
  374.                 outformat.comment);
  375.     }
  376.     /* Very Important: 
  377.      * Effect fabrication and start is called AFTER files open.
  378.      * Effect may write out data beforehand, and
  379.      * some formats don't know their sample rate until now.
  380.      */
  381.     checkeffect(0);
  382.     /* inform effect about signal information */
  383.     eff.ininfo = informat.info;
  384.     eff.outinfo = outformat.info;
  385.     (* eff.h->start)(&eff);
  386.     istart = 0;
  387.     while((isamp = (*informat.h->read)(&informat,&ibuf[istart],
  388.             (long) BUFSIZ-istart))>0) {
  389.         long *ib = ibuf;
  390.  
  391.         isamp += istart;
  392.         /* Do volume before effect or after?  idunno */
  393.         if (dovolume) for (i = 0; i < isamp; i++)
  394.             ibuf[i] = volumechange(ibuf[i]);
  395.         osamp = sizeof(obuf) / sizeof(long);
  396.         /* Effect (i.e. rate change) may do different sizes I and O */
  397.         while (isamp) {
  398.             idone = isamp;
  399.             odone = osamp;
  400.             (* eff.h->flow)(&eff, ib, obuf, &idone, &odone);
  401.             /* 
  402.              * kludge!     
  403.              * Effect is stuck.  Start over with new buffer.
  404.              * This can drop samples at end of file. 
  405.              * No effects currently do this, but it could happen.
  406.              */
  407.             if (idone == 0) {
  408.                 int i;
  409.                 for(i = isamp - 1; i; i--)
  410.                     ibuf[i] = ib[i];
  411.                 istart = isamp;
  412.                 isamp = 0;
  413.                 break;
  414.             }
  415.             if (writing && (odone > 0)) 
  416.                 (* outformat.h->write)(&outformat, obuf, (long) odone);
  417.             isamp -= idone;
  418.             ib += idone;
  419.         }
  420.     }
  421.     /* Drain effect out */
  422.     if (writing) {
  423.         odone = sizeof(obuf) / sizeof(long);
  424.         (* eff.h->drain)(&eff, obuf, &odone);
  425.         if (odone > 0)
  426.             (* outformat.h->write)(&outformat, obuf, (long) odone);
  427.         /* keep calling it until it returns a partial buffer */
  428.         while (odone == (sizeof(obuf) / sizeof(long))) {
  429.             (* eff.h->drain)(&eff, obuf, &odone);
  430.             if (odone)
  431.              (* outformat.h->write)(&outformat, obuf, (long) odone);
  432.         }
  433.     }
  434.     /* Very Important: 
  435.      * Effect stop is called BEFORE files close.
  436.      * Effect may write out more data after. 
  437.      */
  438.     (* eff.h->stop)(&eff);
  439.     (* informat.h->stopread)(&informat);
  440.     fclose(informat.fp);
  441.     if (writing)
  442.         (* outformat.h->stopwrite)(&outformat);
  443.     if (writing)
  444.         fclose(outformat.fp);
  445. }
  446.  
  447. /*
  448.  * Check that we have a known format suffix string.
  449.  */
  450. void
  451. gettype(formp)
  452. ft_t formp;
  453. {
  454.     char **list;
  455.     int i;
  456.  
  457.     if (! formp->filetype)
  458. fail("Must give file type for %s file, either as suffix or with -t option",
  459. formp->filename);
  460.     for(i = 0; formats[i].names; i++) {
  461.         for(list = formats[i].names; *list; list++) {
  462.             char *s1 = *list, *s2 = formp->filetype;
  463.             if (! strcmpcase(s1, s2))
  464.                 break;    /* not a match */
  465.         }
  466.         if (! *list)
  467.             continue;
  468.         /* Found it! */
  469.         formp->h = &formats[i];
  470.         return;
  471.     }
  472.     if (! strcmpcase(formp->filetype, "snd")) {
  473.         verbose = 1;
  474.         report("File type '%s' is used to name several different formats.", formp->filetype);
  475.         report("If the file came from a Macintosh, it is probably");
  476.         report("a .ub file with a sample rate of 11025 (or possibly 5012 or 22050).");
  477.         report("Use the sequence '-t .ub -r 11025 file.snd'");
  478.         report("If it came from a PC, it's probably a Soundtool file.");
  479.         report("Use the sequence '-t .sndt file.snd'");
  480.         report("If it came from a NeXT, it's probably a .au file.");
  481.         fail("Use the sequence '-t .au file.snd'\n");
  482.     }
  483.     fail("File type '%s' of %s file is not known!",
  484.         formp->filetype, formp->filename);
  485. }
  486.  
  487. copyformat(ft, ft2)
  488. ft_t ft, ft2;
  489. {
  490.     int noise = 0;
  491.     if (ft2->info.rate == 0) {
  492.         ft2->info.rate = ft->info.rate;
  493.         noise = 1;
  494.     }
  495.     if (outformat.info.size == -1) {
  496.         ft2->info.size = ft->info.size;
  497.         noise = 1;
  498.     }
  499.     if (outformat.info.style == -1) {
  500.         ft2->info.style = ft->info.style;
  501.         noise = 1;
  502.     }
  503.     if (outformat.info.channels == -1) {
  504.         ft2->info.channels = ft->info.channels;
  505.         noise = 1;
  506.     }
  507.     if (outformat.comment == NULL) {
  508.         ft2->comment = ft->comment;
  509.         noise = 1;
  510.     }
  511.     return noise;
  512. }
  513.  
  514. cmpformats(ft, ft2)
  515. ft_t ft, ft2;
  516. {
  517.     int noise = 0;
  518.     float abs;
  519.  
  520. }
  521.  
  522. /* check that all settings have been given */
  523. checkformat(ft) 
  524. ft_t ft;
  525. {
  526.     if (ft->info.rate == 0)
  527.         fail("Sampling rate for %s file was not given\n", ft->filename);
  528.     if ((ft->info.rate < 100) || (ft->info.rate > 50000))
  529.         fail("Sampling rate %u for %s file is bogus\n", 
  530.             ft->info.rate, ft->filename);
  531.     if (ft->info.size == -1)
  532.         fail("Data size was not given for %s file\nUse one of -b/-w/-l/-f/-d/-D", ft->filename);
  533.     if (ft->info.style == -1)
  534.         fail("Data style was not given for %s file\nUse one of -s/-u/-U/-A", ft->filename);
  535.     /* it's so common, might as well default */
  536.     if (ft->info.channels == -1)
  537.         ft->info.channels = 1;
  538.     /*    fail("Number of output channels was not given for %s file",
  539.             ft->filename); */
  540. }
  541.  
  542. /*
  543.  * If no effect given, decide what it should be.
  544.  */
  545. void
  546. checkeffect(effp)
  547. eff_t effp;
  548. {
  549.     int already = (eff.name != (char *) 0);
  550.     char *rate = 0, *chan = 0;
  551.     int i;
  552.  
  553.     for (i = 0; effects[i].name; i++) {
  554.         if (!chan && (effects[i].flags & EFF_CHAN))
  555.             chan = effects[i].name;
  556.         if (! rate && (effects[i].flags & EFF_RATE))
  557.             rate = effects[i].name;
  558.     }
  559.  
  560.     if (eff.name && ! writing)
  561.         return;
  562.  
  563.     /* 
  564.      * Require mixdown for channel mismatch.
  565.      * XXX Doesn't handle channel expansion.  Need an effect for this.
  566.      * Require one of the rate-changers on a rate change.
  567.      * Override a rate change by explicitly giving 'copy' command.
  568.      */
  569.     if (informat.info.channels != outformat.info.channels) {
  570.         if (eff.name && !(eff.h->flags & EFF_CHAN))
  571.             fail("Need to do change number of channels first.  Try the '%s' effect.", chan);
  572.         if (! eff.name) {
  573.             eff.name = chan;
  574.             report(
  575. "Changing %d input channels to %d output channels with '%s' effect\n",
  576.             informat.info.channels, outformat.info.channels, chan);
  577.             geteffect(&eff);
  578.         }
  579.     } 
  580.     /* 
  581.      * Be liberal on rate difference errors.
  582.      * Note that the SPARC 8000-8192 problem
  583.      * comes in just under the wire.  XXX
  584.      *
  585.       * Bogus.  Should just do a percentage.
  586.      */
  587.     if (abs(informat.info.rate - outformat.info.rate) > 200) {
  588.         if (eff.name && !(eff.h->flags & EFF_RATE))
  589.             fail("Need to do rate change first.  Try the '%s' effect.", 
  590.             rate);
  591.         if (! eff.name) {
  592.             eff.name = rate;
  593.             report(
  594. "Changing sample rate %u to rate %u via noisy 'rate' effect\n",
  595.             informat.info.rate, outformat.info.rate);
  596.             geteffect(&eff);
  597.         }
  598.     }
  599.     /* don't need to change anything */
  600.     if (! eff.name)
  601.         eff.name = "copy";
  602.     if (! already) {
  603.         geteffect(&eff);
  604.         /* give default opts for manufactured effect */
  605.         (* eff.h->getopts)(&eff, 0, (char *) 0);
  606.     }
  607. }
  608.  
  609. /*
  610.  * Check that we have a known effect name.
  611.  */
  612. void
  613. geteffect(effp)
  614. eff_t effp;
  615. {
  616.     int i;
  617.  
  618.     for(i = 0; effects[i].name; i++) {
  619.         char *s1 = effects[i].name, *s2 = effp->name;
  620.         while(*s1 && *s2 && (tolower(*s1) == tolower(*s2)))
  621.             s1++, s2++;
  622.         if (*s1 || *s2)
  623.             continue;    /* not a match */
  624.         /* Found it! */
  625.         effp->h = &effects[i];
  626.         return;
  627.     }
  628.     /* Guido Van Rossum fix */
  629.     fprintf(stderr, "Known effects:");
  630.     for (i = 0; effects[i].name; i++)
  631.         fprintf(stderr, "\t%s\n", effects[i].name);
  632.     fail("\nEffect '%s' is not known!", effp->name);
  633. }
  634.  
  635. /* Guido Van Rossum fix */
  636. statistics() {
  637.     if (dovolume && clipped > 0)
  638.         report("Volume change clipped %d samples", clipped);
  639. }
  640.  
  641. long volumechange(y)
  642. long y;
  643. {
  644.     double y1;
  645.  
  646.     y1 = y * volume;
  647.     if (y1 < -2147483647.0) {
  648.         y1 = -2147483647.0;
  649.         clipped++;
  650.     }
  651.     else if (y1 > 2147483647.0) {
  652.         y1 = 2147483647.0;
  653.         clipped++;
  654.     }
  655.  
  656.     return y1;
  657. }
  658.  
  659. #if    defined(unix) || defined(AMIGA)
  660. filetype(fd)
  661. int fd;
  662. {
  663.     struct stat st;
  664.  
  665.     fstat(fd, &st);
  666.  
  667.     return st.st_mode & S_IFMT;
  668. }
  669. #endif
  670.  
  671. char *usagestr = 
  672. "[ -V -S ] [ fopts ] ifile [ fopts ] ofile [ effect [ effopts ] ]\nfopts: -r rate -v volume -c channels -s/-u/-U/-A -b/-w/-l/-f/-d/-D -x\neffects and effopts: various";
  673.  
  674. usage(opt)
  675. char *opt;
  676. {
  677. #ifndef    DOS
  678.     /* single-threaded machines don't really need this */
  679.     fprintf(stderr, "%s: ", myname);
  680. #endif
  681.     fprintf(stderr, "Usage: %s", usagestr);
  682.     if (opt)
  683.         fprintf(stderr, "\nFailed at: %s\n", opt);
  684.     exit(1);
  685. }
  686.  
  687. void
  688. #ifdef    __STDC__
  689. report(char *fmt, ...)
  690. #else
  691. report(va_alist) 
  692. va_dcl
  693. #endif
  694. {
  695.     va_list args;
  696. #ifndef    __STDC__
  697.     char *fmt;
  698. #endif
  699.  
  700.     if (! verbose)
  701.         return;
  702. #ifndef    DOS
  703.     /* single-threaded machines don't really need this */
  704.     fprintf(stderr, "%s: ", myname);
  705. #endif
  706. #ifdef    __STDC__
  707.     va_start(args, fmt);
  708. #else
  709.     va_start(args);
  710.     fmt = va_arg(args, char *);
  711. #endif
  712.     vfprintf(stderr, fmt, args);
  713.     va_end(args);
  714.     fprintf(stderr, "\n");
  715. }
  716.  
  717. void
  718. #ifdef    __STDC__
  719. fail(char *fmt, ...)
  720. #else
  721. fail(va_alist) 
  722. va_dcl
  723. #endif
  724. {
  725.     va_list args;
  726. #ifndef    __STDC__
  727.     char *fmt;
  728. #endif
  729.  
  730. #ifndef    DOS
  731.     /* single-threaded machines don't really need this */
  732.     fprintf(stderr, "%s: ", myname);
  733. #endif
  734. #ifdef    __STDC__
  735.     va_start(args, fmt);
  736. #else
  737.     va_start(args);
  738.     fmt = va_arg(args, char *);
  739. #endif
  740.     vfprintf(stderr, fmt, args);
  741.     va_end(args);
  742.     fprintf(stderr, "\n");
  743.     exit(2);
  744. }
  745.  
  746.  
  747. strcmpcase(s1, s2)
  748. char *s1, *s2;
  749. {
  750.     while(*s1 && *s2 && (tolower(*s1) == tolower(*s2)))
  751.         s1++, s2++;
  752.     return *s1 - *s2;
  753. }
  754.